package com.yesep.handler;


import cn.hutool.core.bean.BeanException;
import com.yesep.common.service.RpcCommonService;
import com.yesep.constant.Constants;
import com.yesep.message.MessageInterface;
import com.yesep.model.DataText;
import com.yesep.model.MessageBaseModel;
import com.yesep.netty.NettyChannelManager;
import com.yesep.utils.*;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @program: gateway
 * @description: 报文处理
 * @author: quliang
 * @create: 2019-07-14 12:23
 **/

public class MessageHandler {
    private final static Logger log = LoggerFactory.getLogger(MessageHandler.class);

    /**
     * 从消息包中取得相关的内容长度
     *
     * @param packageStr
     * @return
     */
    public static String getMessageFromPackage(String packageStr) {
        String message = null;
        if (!Objects.equals(packageStr, null)) {
            try {
                String lengthStr = packageStr.substring(Constants.PACKAGE_HEADER_STR.length(), Constants.PACKAGE_HEADER_STR.length() + Constants.PACKAGE_CONTENT_LENGTH_STR);
                int length = Integer.parseInt(lengthStr);
                message = packageStr.substring(Constants.PACKAGE_HEADER_STR.length() + Constants.PACKAGE_CONTENT_LENGTH_STR, Constants.PACKAGE_HEADER_STR.length() + Constants.PACKAGE_CONTENT_LENGTH_STR + length);
            } catch (Exception e) {
                log.error("function[getMessageFromPackage] packageStr[{}] error:", packageStr, e.getMessage());
            }

        }
        return message;
    }

    /**
     * 将消息封装成数据包
     *
     * @param message
     * @return
     */
    public static String tranMessageToPackage(String message) {
        StringBuffer packageStr = new StringBuffer();

        if (!Objects.equals(message, null)) {
            packageStr.append(Constants.PACKAGE_HEADER_STR);
            String messageLength = paddingLength(String.valueOf(message.length()), 4, 0, "0");
            packageStr.append(messageLength);
            packageStr.append(message);
            packageStr.append(crc16(message));
            packageStr.append(Constants.PACKAGE_TAILED_R_STR);
            packageStr.append(Constants.PACKAGE_TAILED_N_STR);
        }
        return packageStr.toString();
    }

    /**
     * 根据正则表达式找出相关字符串
     *
     * @param message
     * @param expression
     * @return
     */
    public static String getStringForExpression(String message, String expression) {
        Pattern pattern = Pattern.compile(expression);
        Matcher matcher = pattern.matcher(message);
        String resultStr = null;
        if (matcher.find()) {
            resultStr = matcher.group(0);
        }
        return resultStr;
    }

    /**
     * 将消息字符串转换成相关的vo对象
     *
     * @param message
     * @return
     */
    public static MessageBaseModel tranStringResponseMessageBaseModel(String message) {
        MessageBaseModel messageBaseModel = new MessageBaseModel();
        messageBaseModel.setQN(getValueSplitString(getStringForExpression(message, Constants.QN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setST(getValueSplitString(getStringForExpression(message, Constants.ST_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setCN(getValueSplitString(getStringForExpression(message, Constants.CN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setPW(getValueSplitString(getStringForExpression(message, Constants.PW_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setMN(getValueSplitString(getStringForExpression(message, Constants.MN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setFlag(getValueSplitString(getStringForExpression(message, Constants.FLAG_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setCP(getValueMapSplitString(getStringForExpression(message, Constants.CP_EXPRESSION).replaceAll(",", ";"), Constants.EXTEND_MESSAGE_SPLIT, Constants.MESSAGE_KEY_VALUE_SPLIT));
        return messageBaseModel;
    }


    /**
     * 将消息字符串转换成相关的vo对象
     *
     * @param message
     * @return
     */
    public static MessageBaseModel tranStringMessageBaseModel(String message) {
        MessageBaseModel messageBaseModel = new MessageBaseModel();
        if (!message.trim().startsWith(Constants.PACKAGE_HEADER_STR)) {
            messageBaseModel.setErrorMessage("包头格式错误，请确认请求包头是否为[" + Constants.PACKAGE_HEADER_STR + "].");
            return messageBaseModel;
        }
        String lengthStr = message.substring(Constants.PACKAGE_HEADER_STR.length(), Constants.PACKAGE_HEADER_STR.length() + Constants.PACKAGE_CONTENT_LENGTH_STR);
        int length = 0;
        try {
            length = Integer.parseInt(lengthStr);
        } catch (Exception e) {
            messageBaseModel.setErrorMessage("内容长度格式错误，请确认内容长度是否为[" + lengthStr + "].");
            return messageBaseModel;
        }
        if ((message.length() - Constants.PACKAGE_HEADER_STR.length() - Constants.PACKAGE_CONTENT_LENGTH_STR - 4) < length) {
            messageBaseModel.setErrorMessage("消息格式错误，消息内容长度不足，请确认内容长度是否为[" + lengthStr + "].");
            return messageBaseModel;
        }
        messageBaseModel.setQN(getValueSplitString(getStringForExpression(message, Constants.QN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setST(getValueSplitString(getStringForExpression(message, Constants.ST_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setCN(getValueSplitString(getStringForExpression(message, Constants.CN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setPW(getValueSplitString(getStringForExpression(message, Constants.PW_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setMN(getValueSplitString(getStringForExpression(message, Constants.MN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setFlag(getValueSplitString(getStringForExpression(message, Constants.FLAG_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
        messageBaseModel.setCP(getValueMapSplitString(getStringForExpression(message, Constants.CP_EXPRESSION).replaceAll(",", Constants.BASE_MESSAGE_SPLIT), Constants.EXTEND_MESSAGE_SPLIT, Constants.MESSAGE_KEY_VALUE_SPLIT));
        return messageBaseModel;
    }

    /**
     * 将消息字符串转换成相关的vo对象
     *
     * @param message
     * @return
     */
    public static Map tranStringMap(String message) {
        Map<String, Object> messageMap = new HashMap<>(10);
        try {
            messageMap.put("PNUM", getValueSplitString(getStringForExpression(message, Constants.PNUM_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
            messageMap.put("PNO", getValueSplitString(getStringForExpression(message, Constants.PNO_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
            messageMap.put("QN", getValueSplitString(getStringForExpression(message, Constants.QN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
            messageMap.put("ST", getValueSplitString(getStringForExpression(message, Constants.ST_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
            messageMap.put("CN", getValueSplitString(getStringForExpression(message, Constants.CN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
            messageMap.put("PW", getValueSplitString(getStringForExpression(message, Constants.PW_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
            messageMap.put("MN", getValueSplitString(getStringForExpression(message, Constants.MN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
            messageMap.put("Flag", getValueSplitString(getStringForExpression(message, Constants.FLAG_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));
            messageMap.put("CP", getValueMapSplitString(Objects.equals(getStringForExpression(message, Constants.CP_EXPRESSION), null) ? null : getStringForExpression(message, Constants.CP_EXPRESSION).replaceAll(Constants.PACKAGE_EQUAL_SPLIT, Constants.BASE_MESSAGE_SPLIT), Constants.EXTEND_MESSAGE_SPLIT, Constants.MESSAGE_KEY_VALUE_SPLIT));
        } catch (Exception ex) {
            log.error("Class [MessageHandler] method[tranStringMap] 数据报文 String 转换 Map 失败");
            ex.printStackTrace();
        }
        return messageMap;
    }

    /**
     * 根据分隔符取得相关的值
     *
     * @param message
     * @param splitChar
     * @return
     */
    @SuppressWarnings("finally")
    public static String getValueSplitString(String message, String splitChar) {
        System.out.println(message);
        if (Objects.equals(message, null)) return null;
        String result = null;
        try {
            if (!Objects.equals(message, null) && message.indexOf(splitChar) != -1) {
                result = message.split(splitChar)[1];
            }
        } catch (Exception e) {
            log.error("function[getValueSplitString] message[{}] error:", message, e.getMessage());
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 根据分隔符取得相关的值
     *
     * @param message
     * @param arraySplitChar
     * @param keyValueSplitChar
     * @return
     */
    public static Map getValueMapSplitString(String message, String arraySplitChar, String keyValueSplitChar) {
        Map valueMap = new HashMap();
        try {
            if (!Objects.equals(message, null)) {
                message = message.substring(message.indexOf(Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT) + Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT.length(), message.lastIndexOf(Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT));
                String[] keyValueArray = message.split(arraySplitChar);
                for (String keyValue : keyValueArray) {
                    String[] tempKeyValue = keyValue.split(keyValueSplitChar);
                    if (tempKeyValue.length < 2) continue;
                    if (valueMap.containsKey(tempKeyValue[0])) {
                        Object tempMapValue = valueMap.get(tempKeyValue[0]);
                        if (tempMapValue instanceof List) {
                            ((List) tempMapValue).add(tempKeyValue[1]);
                        } else {
                            List tempMapValueList = new ArrayList();
                            tempMapValueList.add(valueMap.get(tempKeyValue[0]));
                            tempMapValueList.add(tempKeyValue[1]);
                            valueMap.put(tempKeyValue[0], tempMapValueList);
                        }
                    } else {
                        valueMap.put(tempKeyValue[0], tempKeyValue[1]);
                    }
                }
            }
        } catch (Exception e) {
            log.error("function[getValueMapSplitString] message[{}] arraySplitChar[{}] keyValueSplitChar[{}] error:", message, arraySplitChar, keyValueSplitChar, e.getMessage());
            e.printStackTrace();
        }
        return valueMap;
    }

    /**
     * @param map
     * @param tranExpressionStr
     * @return
     */
    public static String tranMapToString(Map map, String tranExpressionStr) {
        StringBuffer message = new StringBuffer(120);
        if (!Objects.equals(map, null)) {
//            log.info("function[tranMapToString] map [{}] tranExpressionStr[{}]", map.toString(), tranExpressionStr);
            try {
                String[] expressionStrArray = tranExpressionStr.split(Constants.TRAN_MODEL_MESSAGE_EXPRESSION_SPLIT);
                for (String expressionStr : expressionStrArray) {
                    if (expressionStr.indexOf("{") == -1) {
                        Object valueObj = map.get(expressionStr);
                        if (!Objects.equals(valueObj, null)) {
                            if (!Objects.equals(message, null) && message.length() > 0) {
                                message.append(";");
                            }
                            message.append(expressionStr).append("=").append(valueObj.toString());
                        }
                    } else {
                        String filedName = expressionStr.substring(0, expressionStr.indexOf("{"));
                        String[] extendMessageKeyArray = expressionStr.substring(expressionStr.indexOf("{") + 1, expressionStr.lastIndexOf("}")).split(",");
                        Object valueObj = map.get(filedName);
                        Map<String, String> tempRepeateKeyMap = new HashMap<String, String>();
                        if (valueObj instanceof Map) {
                            message.append(";").append(filedName).append("=");
                            message.append(Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT);
                            StringBuffer extendMessage = new StringBuffer(50);
                            for (String extendMessageKey : extendMessageKeyArray) {
                                Map valueObjMap = (Map) valueObj;
                                if (valueObjMap.containsKey(extendMessageKey)) {
                                    Object tempValueObj = valueObjMap.get(extendMessageKey);
                                    if (tempValueObj instanceof String) {
                                        if (extendMessage != null && extendMessage.length() > 0) {
                                            extendMessage.append(",");
                                        }
                                        extendMessage.append(extendMessageKey).append("=").append(valueObjMap.get(extendMessageKey));
                                    } else if (tempValueObj instanceof List) {
                                        if (tempRepeateKeyMap.containsKey(extendMessageKey))
                                            continue;
                                        tempRepeateKeyMap.put(extendMessageKey, "true");
                                        for (Object tempValueStr : (List) tempValueObj) {
                                            if (!Objects.equals(extendMessage, null)) {
                                                extendMessage.append(",");
                                            }
                                            extendMessage.append(extendMessageKey).append("=").append(tempValueStr);
                                        }
                                    }
                                }
                            }
                            message.append(extendMessage);
                            message.append(Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error("function[tranMapToString] map [{}]" + " tranExpressionStr[{}] error:", map.toString(), tranExpressionStr, e.getMessage());
            }
        }
        return message.toString();
    }

    /**
     * 从相关的model对象转换成相关的string对象
     *
     * @param messageBaseModel
     * @param tranExpressionStr
     * @return
     */
    public static String tranMessageModelToString(MessageBaseModel messageBaseModel, String tranExpressionStr) {
        StringBuffer message = new StringBuffer(120);
        if (messageBaseModel != null) {
//            log.info("function[tranMessageModelToString] messageBaseModel[{}]" + " tranExpressionStr[{}]", messageBaseModel.toString(), tranExpressionStr);
            try {
                String[] expressionStrArray = tranExpressionStr.split(Constants.TRAN_MODEL_MESSAGE_EXPRESSION_SPLIT);

                for (String expressionStr : expressionStrArray) {
                    if (expressionStr.indexOf("{") == -1) {
                        Object valueObj = getFieldValueFromObject(messageBaseModel, expressionStr);
                        if (!Objects.equals(valueObj, null)) {
                            if (message != null && message.length() > 0) {
                                message.append(Constants.TRAN_MODEL_MESSAGE_EXPRESSION_SPLIT);
                            }
                            message.append(expressionStr).append("=").append(valueObj.toString());
                        }
                    } else {
                        String filedName = expressionStr.substring(0, expressionStr.indexOf("{"));
                        String[] extendMessageKeyArray = expressionStr.substring(expressionStr.indexOf("{") + 1, expressionStr.lastIndexOf("}")).split(",");
                        Object valueObj = getFieldValueFromObject(messageBaseModel, filedName);
                        Map<String, String> tempRepeateKeyMap = new HashMap<String, String>();

                        if (valueObj instanceof Map) {
                            message.append(";").append(filedName).append("=");
                            message.append(Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT);
                            StringBuffer extendMessage = new StringBuffer();
                            for (String extendMessageKey : extendMessageKeyArray) {
                                Map valueObjMap = (Map) valueObj;
                                if (valueObjMap.containsKey(extendMessageKey)) {
                                    Object tempValueObj = valueObjMap.get(extendMessageKey);
                                    if (tempValueObj instanceof String) {
                                        if (!Objects.equals(extendMessage, null)) {
                                            extendMessage.append(",");
                                        }
                                        extendMessage.append(extendMessageKey).append("=").append(valueObjMap.get(extendMessageKey));
                                    } else if (tempValueObj instanceof List) {
                                        if (tempRepeateKeyMap.containsKey(extendMessageKey))
                                            continue;
                                        tempRepeateKeyMap.put(extendMessageKey, "true");
                                        for (Object tempValueStr : (List) tempValueObj) {
                                            if (!Objects.equals(extendMessage, null)) {
                                                extendMessage.append(",");
                                            }
                                            extendMessage.append(extendMessageKey).append("=").append(tempValueStr);
                                        }
                                    }
                                }
                            }
                            message.append(extendMessage).append(Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT);
                        }
                    }

                }
            } catch (Exception e) {
                log.error("function[tranMessageModelToString] messageBaseModel[{}]" + " tranExpressionStr[{}] error:", messageBaseModel.toString(), tranExpressionStr, e.getMessage());
            }
        }
        return message.toString();
    }


    /**
     * 通过对象、属性名拿到属性值
     *
     * @param obj
     * @param fieldName
     * @return
     */
    public static Object getFieldValueFromObject(Object obj, String fieldName) {
        Object value = null;
        try {
            Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            value = field.get(obj);
        } catch (Exception e) {
            log.error("function[getObjectFromMessageBaseModel] messageBaseModel[{}]" + " fieldName[{}] error:", fieldName, e.getMessage());
        }
        return value;
    }

    /**
     * 从实体类中取出相关的对象的值
     *
     * @param messageBaseModel
     * @param fieldName
     * @return
     */
    @SuppressWarnings("finally")
    public static Object getObjectFromMessageBaseModel(MessageBaseModel messageBaseModel, String fieldName) {
        Object value = null;
        try {
            Class messageBaseModelClass = messageBaseModel.getClass();
            String getMethodName = "get" + fieldName;
            value = messageBaseModelClass.getMethod(getMethodName).invoke(messageBaseModel);
        } catch (Exception e) {
            log.error("function[getObjectFromMessageBaseModel] messageBaseModel[{}]" + " fieldName[{}] error:", messageBaseModel.toString(), fieldName, e.getMessage());
        }
        return value;
    }


    /**
     * 发送消息给客户端
     * mn设备唯一编号或者是 /ip:port  IP地址+端口
     *
     * @param mn
     * @param message
     */
    public static void sendMessageToClient(String mn, String message) {
        try {
            Channel channel = NettyChannelManager.getInstance().getChannelByMn(mn);
            if (!Objects.equals(channel, null) && !Objects.equals(message, null)) {
                channel.writeAndFlush(message);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 发送消息给客户端，并插入相关的报文
     *
     * @param cn
     * @param mn
     * @param cmd
     * @return
     */
    //   public static DataText sendRemoteControllerToClient(String cn, String st, String mn, String polId, String cmd) {
    //Iterator iter = Constants.SITE_INFO_MAP.entrySet().iterator();
//        DataText dt = null;
//        // while (iter.hasNext()) {
//        // Map.Entry entry = (Map.Entry) iter.next();
////        SiteModel siteModel = DataManager.getSiteModelFromCache(mn);
//        MessageData siteModel = new MessageData();
//
//        String status = Constants.DATA_TEXT_STATUS_SUCCESS;
//        String desc = "";
//        Date sysDate = new Date();
//        MessageBaseModel cmdMessageBaseModel = new MessageBaseModel();
//        String currentSystetimestamp = DateUtils.datetimestampToNoSplashString(sysDate);
//        cmdMessageBaseModel.setQN(currentSystetimestamp);
//        cmdMessageBaseModel.setST(st);
//        cmdMessageBaseModel.setCN(cn);
//        cmdMessageBaseModel.setPW(siteModel.getPW());
//        cmdMessageBaseModel.setMN(siteModel.getMN());
//        cmdMessageBaseModel.setFlag(String.valueOf(Constants.IS_RESPONSE_YES));
//        cmdMessageBaseModel.getCP().put("PolId", polId);
//        cmdMessageBaseModel.getCP().put("CMD", cmd);
//        String cmdMessageStr = MessageHandler.tranMessageModelToString(cmdMessageBaseModel, Constants.CMD_MESSAGE_TEMPLATE_MAP.get(cn));
//        String cmdPackageMessageStr = MessageHandler.tranMessageToPackage(cmdMessageStr);
//        String hostAddress = "";
//
//
//        if (null != siteModel) {
////            IoSession ioSession = siteModel.getSession();
//            Channel channel = siteModel.getChannel();
//            if (null == channel) {
//                status = Constants.DATA_TEXT_STATUS_FAILED;
//                desc = "站点【" + mn + "】离线!";
//            } else {
//                try {
//                    //MessageHandler.stringToIoBuffer(cmdPackageMessageStr);
//                    channel.writeAndFlush(cmdPackageMessageStr);
//                } catch (Exception e) {
//                    status = Constants.DATA_TEXT_STATUS_FAILED;
//                    desc = "站点通讯异常【" + mn + "】," + e.getMessage();
//                }
//            }
//            hostAddress = siteModel.getHost();
//        } else {//站点为空，记录日志
//            status = Constants.DATA_TEXT_STATUS_FAILED;
//            desc = "查找不到相关站点,请确认MN【" + mn + "】是否配置正确!";
//        }
//        if (hostAddress == null || hostAddress.equals("")) {
//            hostAddress = "unknown";
//            status = Constants.DATA_TEXT_STATUS_FAILED;
//            desc = "站点MN【" + mn + "】离线!";
//        }
//        //dt = DataManager.getServerMessageManager().saveSendMessage(hostAddress, cmdPackageMessageStr, cmdMessageBaseModel, status, desc);
//        dt = DataManager.saveSendMessage(hostAddress, cmdPackageMessageStr, cmdMessageBaseModel, status, desc);
//
//        return dt;
//    }

    /**
     * 发送消息给客户端，并插入相关的报文
     *
     * @param cn
     * @param mn
     * @param cp
     * @return
     */
//    public static DataText sendRemoteControllerToClient(String cn, String st, String mn, Map cp) {
//        //Iterator iter = Constants.SITE_INFO_MAP.entrySet().iterator();
//        DataText dt = null;
//        // while (iter.hasNext()) {
//        // Map.Entry entry = (Map.Entry) iter.next();
//        //MessageBaseModel siteModel = DataManager.getSiteModelFromCache(mn);
//        MessageData messageData = new MessageData();
//
//        String status = Constants.DATA_TEXT_STATUS_SUCCESS;
//        String desc = "";
//        Date sysDate = new Date();
//
//        //通讯包实体
//        MessageBaseModel cmdMessageBaseModel = new MessageBaseModel();
//
//        String currentSystetimestamp = DateUtils.datetimestampToNoSplashString(sysDate);
//        cmdMessageBaseModel.setQN(currentSystetimestamp);
//        cmdMessageBaseModel.setST(st);
//        cmdMessageBaseModel.setCN(cn);
//        cmdMessageBaseModel.setPW(messageData.getPW());
//        cmdMessageBaseModel.setMN(messageData.getMN());
//        cmdMessageBaseModel.setFlag(String.valueOf(Constants.IS_RESPONSE_YES));
//        cmdMessageBaseModel.setCP(cp);
//
//        String cmdMessageStr = MessageHandler.tranMessageModelToString(cmdMessageBaseModel, Constants.CMD_MESSAGE_TEMPLATE_MAP.get(cn));
//        String cmdPackageMessageStr = MessageHandler.tranMessageToPackage(cmdMessageStr);
//        String hostAddress = "";
//        if (null != messageData) {
//            Channel channel = messageData.getChannel();
//
//            if (null == channel) {
//                status = Constants.DATA_TEXT_STATUS_FAILED;
//                desc = "站点【" + mn + "】离线!";
//            } else {
//                try {
//                    //MessageHandler.stringToIoBuffer(cmdPackageMessageStr)
//                    channel.writeAndFlush(cmdPackageMessageStr);
//                } catch (Exception e) {
//                    status = Constants.DATA_TEXT_STATUS_FAILED;
//                    desc = "站点通讯异常【" + mn + "】," + e.getMessage();
//                }
//            }
//            hostAddress = messageData.getHost();
//        } else {//站点为空，记录日志
//            status = Constants.DATA_TEXT_STATUS_FAILED;
//            desc = "查找不到相关站点,请确认MN【" + mn + "】是否配置正确!";
//        }
//
//        if (hostAddress == null || hostAddress.equals("")) {
//            hostAddress = "unknown";
//            status = Constants.DATA_TEXT_STATUS_FAILED;
//            desc = "站点MN【" + mn + "】离线!";
//        }
//        //  dt = DataManager.getServerMessageManager().saveSendMessage(hostAddress, cmdPackageMessageStr, cmdMessageBaseModel, status, desc);
//        //}
//        return dt;
//    }

    /**
     * 补充字符串
     *
     * @param str
     * @param length
     * @param type   0:左端 1:右端
     * @param addStr
     * @return
     */
    public static String paddingLength(String str, int length, int type, String addStr) {
        int tempLength = str.length();
        if (tempLength >= length) {
            return str;
        } else {
            for (int i = tempLength; i < length; i++) {
                if (type == 0) {
                    //左边补
                    str = addStr + str;
                } else if (type == 1) {
                    // 右边补
                    str = str + addStr;
                }
            }
            return str;
        }
    }


    public static byte[] short2Byte(short number) {
        int temp = number;
        byte[] b = new byte[2];
        for (int i = 0; i < b.length; i++) {
            b[i] = new Integer(temp & 0xff).byteValue();// 将最低位保存在最低位
            temp = temp >> 8; // 向右移8位
        }
        return b;
    }

    // 字节转化为十六进制字符串
    public static String bytesToHexString(byte[] src) {
        // byte[] src = reverseBytes(src1);
        StringBuffer stringBuilder = new StringBuffer();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            // 变成正数
            int v = src[i] & 0xFF;
            // Integer.toHexString 转化成十六进制
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 将byte[]转换成string
     *
     * @param b
     * @return
     */
    public static String byteToString(byte[] b) {
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            stringBuffer.append((char) b[i]);
        }
        return stringBuffer.toString();
    }

    /**
     * 处理业务
     *
     * @param channel
     * @param msg
     */
    public static void doBusiness(Channel channel, String msg) {
        long startTime = System.currentTimeMillis();
        String socketAddress = channel.remoteAddress().toString();
        System.out.println(socketAddress + "  Server -> " + msg.toString());
        NettyChannelManager.getInstance().bindMnAndChannel(socketAddress, channel.id().asLongText());

        String message = msg.trim();
        String[] sendMessageArray = message.split(Constants.PACKAGE_TAILED_RN_STR);
        for (String sendMessage : sendMessageArray) {
//            log.info("Class [{}] remoteAddress:[{}]  message:[{}]", "MessageHandler", socketAddress, sendMessage);

            if (Objects.equals(sendMessage, null)) return;
            //获取应答标记
            String flag = getValueSplitString(getStringForExpression(message, Constants.FLAG_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT);
            log.info("是否进行拆分包应答标记为[{}]", flag);

            //报文没有Flag标志位不一定是第一包,还需要在缓存中获取之前是否是当前有缓存过报文
            if (!Objects.equals(flag, null) || !Objects.equals(CacheUtils.cacheMessageMap.get(socketAddress), null)) {
                //处理分包
                MessageHandler.handlerSubPackage(sendMessage, flag, channel);
                return;
            }

            try {
                System.out.println("success");
                //未分包报文进行校验并返回一个报文实体
                MessageBaseModel messageBaseModel = MessageHandler.tranStringMessageBaseModel(sendMessage.trim());
//                log.info("Class [{}] remoteAddress:[{}]  messageBaseModel:[{}]", "MessageHandler", socketAddress, messageBaseModel);
                //异常报文
                if (!Objects.equals(messageBaseModel.getErrorMessage(), null)) {
                    return;
                }

                handlerMessageChannel(messageBaseModel, channel, message);
            } catch (Exception ex) {
                log.error("通讯异常", ex.getCause());
                ex.printStackTrace();
            }
        }
//        log.info("处理业务时间为:" + (System.currentTimeMillis() - startTime) + "MS");
    }

    /**
     * 根据不同的命令执行不同的实现类
     *
     * @param messageBaseModel
     * @return
     */
    public static Object handlerMessageChannel(MessageBaseModel messageBaseModel, Channel channel, String message) {
        String socketAddress = channel.remoteAddress().toString();

//        DataText dataText = DataManager.parseReceiveMessage(socketAddress, message, messageBaseModel);
        messageBaseModel.setIp(socketAddress);
        messageBaseModel.setMessage(message);

        DataText dataText = DataManager.parseDataMessage(messageBaseModel);

        //解析异常
        if (Objects.equals(Constants.DATA_TEXT_STATUS_FAILED, dataText.getDtStatus())) {
            DataManager.getDataTextService().save(dataText);
            return null;
        }
        //持久化操作
        DataManager.getDataTextService().insert(dataText);

        Map cpDataMap = getValueMapSplitString(getStringForExpression(message, Constants.CP_EXPRESSION).replaceAll(Constants.PACKAGE_EQUAL_SPLIT, Constants.BASE_MESSAGE_SPLIT), Constants.EXTEND_MESSAGE_SPLIT, Constants.MESSAGE_KEY_VALUE_SPLIT);
        DataManager.getEnvPolluteFactorService().save(cpDataMap,dataText);

        System.out.println("save finish");
        //获取 指令、管道、IP端口地址
        String cn = messageBaseModel.getCN();

        log.info("Class [{}] remoteaddress [{}] CN [{}] ", "MessageHandler", socketAddress, cn);
        MessageInterface messageInterface = null;
        try {
            //通过spring来进行不同实现类  Message指令Service 需要转换成类名首字母小写,因为类交给spring管理的时候一般默认使用小写的类名作为bean的id；
            messageInterface = (MessageInterface) SpringUtil.getBean(Constants.MESSAGE_INTERFACE_PREFIX.toLowerCase() + cn + Constants.MESSAGE_INTERFACE_SUFFIX);
        } catch (BeanException ex) {
            log.error("通过spring指定报文实现类报错", ex.getMessage());
        }
        if (!Objects.equals(messageInterface, null)) {
            try {
                messageInterface.handleMessage(channel, messageBaseModel, dataText);
            } catch (Exception ex) {
                log.error("请检查该实现类[{}] 命令编码为[{}]", Constants.MESSAGE_INTERFACE_PREFIX.toLowerCase() + cn + Constants.MESSAGE_INTERFACE_SUFFIX, cn, ex.getMessage());
                ex.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 处理分包
     *
     * @param message
     * @param flag
     * @param channel
     * @return
     */
    public static Object handlerSubPackage(String message, String flag, Channel channel) {
        long startTime = System.currentTimeMillis();

        if (Objects.equals(message.trim(), null)) return null;
        Map messageMap = null;
        //校验报文是否正常
        boolean checkMessage = false;
        //是否应答下位机
        boolean isAnswer = false;
        //ip地址
        String ipAddress = channel.remoteAddress().toString();

        //获取报文数据
        String msg = CacheUtils.cacheMessageMap.get(ipAddress);

        //校验报文
        checkMessage = validationMessage(message);

        //通过标记是否进行分包缓存报文删除
        if (!checkMessage) {
            //持久化分包数据
            CacheUtils.cacheMessageMap.remove(channel.remoteAddress().toString());
            return null;
        }


        //之前是否缓存过数据
        if (Objects.equals(msg, null)) {
            String subStr = message.substring(6, message.lastIndexOf(Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT));
            CacheUtils.cacheMessageMap.put(ipAddress, subStr);
            //第一条报文就生成回复map
            messageMap = MessageHandler.tranStringMap(message);
        } else {
            String cacheMessage = CacheUtils.cacheMessageMap.get(ipAddress);
            if (!Objects.equals(cacheMessage, null)) {
                messageMap = MessageHandler.tranStringMap(message);

                //总包数
                String pNum = (String) messageMap.get("PNUM");
                //当前包号
                String pno = (String) messageMap.get("PNO");
                //获取cp数据段 拼接数据
                String cpContent = getValueSplitString(message, Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT);
                StringBuffer tempMessage = new StringBuffer(Integer.valueOf(pNum) * 10000);
                tempMessage.append(cacheMessage).append(Constants.EXTEND_MESSAGE_SPLIT);
                tempMessage.append(cpContent.substring(0, cpContent.lastIndexOf(Constants.EXTEND_MESSAGE_SPLIT)));
                //放入缓存
                CacheUtils.cacheMessageMap.put(ipAddress, tempMessage.toString());

                //检查当前与缓存报文是否是同一分包
                boolean isSubPackage = checkSubPackage(message, msg);

                //避免重复报文与特殊情况报文
                if (!isSubPackage) {
                    //覆盖掉报文缓存
                    CacheUtils.cacheMessageMap.put(ipAddress, message);
                }

                if (Objects.equals(pNum, null) || Objects.equals(pno, null)) return null;
                //当前包号达到总包数
                if (Objects.equals(pno, pNum)) {
                    String temp = CacheUtils.cacheMessageMap.get(ipAddress);
                    String crc = null;
                    String seqNum = null;
                    int messageLenght = 0;
                    if (!Objects.equals(temp, null)) {
                        messageLenght = temp.length();
                        crc = crc16(temp);
                        seqNum = getSeqNumByLong(messageLenght, 4);
                    }

                    StringBuffer sb = new StringBuffer(Integer.valueOf(pNum) * 10000);
                    sb.append(Constants.PACKAGE_HEADER_STR).append(seqNum);
                    sb.append(temp).append(Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT).append(crc);

                    MessageBaseModel messageBaseModel = MessageHandler.tranStringMessageBaseModel(sb.toString());
                    //保存报文
                    DataManager.getDataMessageService().insert(messageBaseModel);
//                    log.info("当前ip[{}] 报文内容为:[{}]", ipAddress, sb);
                    //持久化报文
                    CacheUtils.cacheMessageMap.remove(ipAddress);
                }
            }
        }

        //解析报文中的标志位Flag
        isAnswer = parseMessageFlag(flag);

        //根据标记是否回复下位机
        if (isAnswer) isResponse(channel, messageMap, Constants.UP_TO_DOWN_RESPONSE_CN, message);

        System.out.println("分包处理时间为:" + (System.currentTimeMillis() - startTime) + "MS");
        return checkMessage;
    }

    /**
     * 解析报文中的标志位Flag
     *
     * @param flag
     * @return
     */
    private static boolean parseMessageFlag(String flag) {
        boolean isAnswer = false;

        if (!Objects.equals(flag, null)) {
            //标志位Flag二进制字符串,不够补0
            String binaryFlag = StringUtils.toBinary(Integer.valueOf(flag), 8);
            if (!Objects.equals(binaryFlag.length(), 8)) return false;

            //D: 是否进行拆分包   1表示包含包数、包号   0表示不包含包数、包号
            String packageSequence = binaryFlag.substring(6, binaryFlag.length() - 1);
            //A: 是否给下位机进行应答     1应答           0不应答
            String isResponse = binaryFlag.substring(binaryFlag.length() - 1);

            //进行拆分包
            if (Objects.equals(Integer.valueOf(packageSequence), Constants.PACKAGE_SEQUENCE_CONTAIN_FLAG)) {
                //是否响应
                if (Objects.equals(Integer.valueOf(isResponse), Constants.IS_RESPONSE_YES)) {
                    isAnswer = true;
                }
            } else {    //没有拆分包
                if (Objects.equals(Integer.valueOf(isResponse), Constants.IS_RESPONSE_YES)) {
                    isAnswer = true;
                }
            }
        }
        return isAnswer;
    }

    /**
     * 校验报文
     *
     * @param message 报文字串
     * @return
     */
    private static boolean validationMessage(String message) {
        String messageData = message.substring(6, message.lastIndexOf(Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT) + 2);
        //获取数据段长度
        int messageLength = messageData.length();
        String headData = getStringForExpression(message, Constants.PACKAGE_HEAD_EXPRESSION);
        int dataLength = 0;
        String datalen = null;
        if (!Objects.equals(headData, null)) {
            datalen = headData.replaceFirst(Constants.PACKAGE_HEADER_STR, "");
            dataLength = Integer.valueOf(datalen);
        }

        //获取报文的CRC16校验码
        String checkCrc16 = message.substring(message.lastIndexOf(Constants.EXTEND_HEADER_TAILE_MESSAGE_SPLIT) + 2);

        String crc16 = crc16(messageData);

        System.out.println(messageLength + "===" + dataLength + "\t" + crc16 + "===" + checkCrc16);
//        System.out.println("===" + Objects.equals(messageLength, dataLength));
//        System.out.println("===" + Objects.equals(crc16, checkCrc16));

        //校验CRC16校验码、数据段长度
        return Objects.equals(messageLength, dataLength) && Objects.equals(crc16, checkCrc16) && message.contains(Constants.PACKAGE_HEADER_STR) && Objects.equals(datalen.length(), 4);
    }

    /**
     * 校验当前与缓存报文是否一致
     *
     * @param message 当前报文
     * @param msg     缓存报文
     * @return
     */
    private static boolean checkSubPackage(String message, String msg) {
        //获取当前报文与缓存中的CN
        String currentCn = getValueSplitString(getStringForExpression(message, Constants.CN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT);
        String cacheCn = getValueSplitString(getStringForExpression(msg, Constants.CN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT);

        //获取当前报文与缓存中的MN
        String currentMn = getValueSplitString(getStringForExpression(message, Constants.MN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT);
        String cacheMn = getValueSplitString(getStringForExpression(msg, Constants.MN_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT);

        //获取当前报文与缓存中的PNUM
        String currentPnum = getValueSplitString(getStringForExpression(message, Constants.PNUM_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT);
        String cachePnum = getValueSplitString(getStringForExpression(msg, Constants.PNUM_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT);


        //获取当前报文与缓存中的DataTime
        String currentDataTime = getValueSplitString(getStringForExpression(message, Constants.DATATIME_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT);
        String cacheDataTime = getValueSplitString(getStringForExpression(msg, Constants.DATATIME_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT);

        return Objects.equals(currentCn, cacheCn) && Objects.equals(currentMn, cacheMn) && Objects.equals(currentPnum, cachePnum) && Objects.equals(currentDataTime, cacheDataTime);
    }

    /**
     * 是否进行响应
     *
     * @param channel    通过管道写回数据
     * @param messageMap 报文实体
     * @param cn         命令
     */
    public static void isResponse(Channel channel, Map messageMap, String cn, String message) {
        if (Objects.equals(channel, null) || Objects.equals(messageMap, null) || Objects.equals(cn, null)) return;

        try {
            //拿到对应响应数据
            String mapToString = tranMapToString(messageMap, Constants.CMD_MESSAGE_TEMPLATE_MAP.get(cn));

            MessageBaseModel messageBaseModel = tranStringMessageBaseModel(mapToString);
            handlerMessageChannel(messageBaseModel, channel, message);
        } catch (Exception ex) {
            ex.printStackTrace();
//            log.error("Class [MessageHandler] 站点通讯异常[{}]", messageMap.get("MN"), ex.getMessage());
        }
    }

    /**
     * @param temp
     * @return 返回CRC16大写校验码
     * @Description: HJ212污染监测 CRC16校验算法
     * @author *****
     */
    public static String crc16(String temp) {
        /*        String temp =
            "ST=32;CN=2011;PW=122333;MN=88888880000005;CP=&&DataTime=20120416225856;060-Rtd=0.06,060-Flag=N;011-Rtd=0.00,011-Flag=N;001-Rtd=7.64,001-Flag=N&&";
        */ // ##0077QN=20120416225111069;ST=91;CN=9021;PW=122333;MN=88888880000006;Flag=1;CP=&&&&4100
        // ##0101QN=20160801085857223;ST=32;CN=1062;PW=100000;MN=010000A8900016F000169DC0;Flag=5 ;CP=&&RtdInterval=30&&1C80
        Integer[] regs = new Integer[temp.length()];
        for (int i = 0; i < temp.length(); i++) {
            regs[i] = (int) temp.charAt(i);
        }
        int por = 0xFFFF;
        for (int j = 0; j < regs.length; j++) {
            por = por >> 8;
            por ^= regs[j];
            for (int i = 0; i < 8; i++) {
                if ((por & 0x01) == 1) {
                    por = por >> 1;
                    por = por ^ 0xa001;
                } else {
                    por = por >> 1;
                }
            }
        }
        return Integer.toHexString(por).toUpperCase();
    }

    public static String getSeqNumByLong(long l, int bitCount) {
        String seqNum = String.format("%0" + bitCount + "d", l);
        return seqNum;
    }


    public static void main(String[] args) {
//        Map<String, Object> map = new HashMap<>();
//        map.put("aa", null);
        String message = "##0466QN=20190723161030000;ST=21;CN=2011;PW=123456;MN=09252062500001;CP=&&DataTime=20190723161030;w01001-Rtd=0.000,w01001-Flag=N;w01003-Rtd=0.000,w01003-Flag=N;w01009-Rtd=0.000,w01009-Flag=N;w01010-Rtd=0.000,w01010-Flag=N;w01014-Rtd=0.000,w01014-Flag=N;w01019-Rtd=1.630,w01019-Flag=N;w21003-Rtd=0.066,w21003-Flag=N;w21001-Rtd=0.040,w21001-Flag=N;w21011-Rtd=0.022,w21011-Flag=N;w01016-Rtd=84.090,w01016-Flag=N;w01022-Rtd=0.000,w01022-Flag=N;w22001-Rtd=0.000,w22001-Flag=N&&E8C1";
        tranStringMap(message);
//       String stringForExpression = getStringForExpression(message, Constants.PNUM_EXPRESSION);
//        String valueSplitString = getValueSplitString(stringForExpression, Constants.MESSAGE_KEY_VALUE_SPLIT);
//        System.out.println(valueSplitString);

//        MessageBaseModel messageBaseModel = tranStringMessageBaseModel(message);
//        System.out.println(messageBaseModel.toString());
//        Object qn = getFieldValueFromObject(messageBaseModel, "QN");
//        System.out.println(qn);
        //        Map messageMap = MessageHandler.tranStringMap(message);
//        String mapToString = tranMapToString(messageMap, Constants.CMD_MESSAGE_TEMPLATE_MAP.get("9014"));
//        System.out.println(mapToString);
//        String binaryFlag = StringUtils.toBinary(Integer.valueOf("7"), 8);
//        System.out.println(binaryFlag);
//        //D: 是否进行拆分包   1表示包含包数、包号   0表示不包含包数、包号
//        String packageSequence = binaryFlag.substring(6, binaryFlag.length() - 1);
//        //A: 是否给下位机进行应答     1应答           0不应答
//        String isResponse = binaryFlag.substring(binaryFlag.length() - 1, 0);
//
//        System.out.println(packageSequence);
//        System.out.println(isResponse);
//        int num = 890;
//        System.out.println(getSeqNumByLong(num, 4));

//        String message = "##0254QN=20190723161030000;Flag=7;ST=21;CN=2011;PUNM=1;PNO=1222;PW=123456;MN=09252062500001;CP=&&DataTime=20190723161030;w01001-Rtd=0.000,w01001-Flag=N;w01003-Rtd=0.000,w01003-Flag=N;w01009-Rtd=0.000,w01009-Flag=N;w01010-Rtd=0.000,w01010-Flag=N;w01014-Rtd=0.000,w01014-Flag=N&&";
//        String substring = message.substring(6, message.length() - 2);
//        System.out.println(substring);
//        System.out.println(getStringForExpression(message, "DataTime=[0-9]*"));
//        System.out.println(getValueSplitString(getStringForExpression(message, "DataTime=[0-9]*"), Constants.MESSAGE_KEY_VALUE_SPLIT));
//        System.out.println(getValueSplitString(getStringForExpression(message, Constants.PNO_EXPRESSION), Constants.MESSAGE_KEY_VALUE_SPLIT));

        //        Map valueMapSplitString = getValueMapSplitString(getStringForExpression(message, Constants.CP_EXPRESSION).replaceAll(",", ";"), Constants.EXTEND_MESSAGE_SPLIT, Constants.MESSAGE_KEY_VALUE_SPLIT);
//        System.out.println(valueMapSplitString);
        //System.out.println(message.substring(0, message.length() - 6));
//        String s = getStringForExpression(message, Constants.CP_EXPRESSION).replaceAll(",", ";");
//        System.out.println(s);
//        System.out.println(s.substring(0, s.length() - 2));

//        System.out.println(s.substring(0,s.length() - 2));
//        StringBuffer sb = new StringBuffer(message);
//        sb.append(";");
//        Map map = tranStringMap(message);
//        String cp = map.get("CP").toString();
//        System.out.println("cp = " + cp);
//        String mapToString = tranMapToString(map, Constants.CMD_MESSAGE_TEMPLATE_MAP.get("9014"));
//        System.out.println("mapToString = " + mapToString);


        // String substring = message.substring(6, message.length() - 4);
//        System.out.println(substring);
//        //9841  E8C1
//        String checkCrc16 = message.substring(message.length() - 4);
//
        //  String crc16 = CRC16(substring);
        // System.out.println(crc16);
//        System.out.println(checkCrc16);
//
//        int length = message.substring(6, message.length() - 4).length();
//        System.out.println();
//        Integer value = Integer.valueOf(getStringForExpression(message, "##\\d{4}").replaceAll("##", ""));
//        System.out.println(value);
//        System.out.println(Objects.equals(length, value));
        //

        //System.out.println(getStringForExpression(message, "##{4}[a-z0-9A-Z]"));
        // System.out.println(Objects.equals(Integer.valueOf("1"),Constants.FLAG_1));
    }

}
